/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.just.dusin.ooii.component.kj;


import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;
import java.util.Properties;


import org.apache.log4j.Logger;
import org.dusin.webcoal.exception.OOIIException;
import org.just.dusin.ooii.component.Sink;
import org.just.dusin.ooii.database.CLYCBean;
import org.just.dusin.ooii.database.DataOf5mBean;
import org.just.dusin.ooii.database.DatabaseConnectionSQL;
import org.just.dusin.ooii.database.MineData;
import org.just.dusin.ooii.database.RealDeviceDao;
import org.just.dusin.ooii.util.NumberUtil;

/**
 *
 * @author Administrator
 */
public class KJSocketSink implements Sink {

    private static final Logger logger = Logger.getLogger(KJSocketSink.class.getName());
    byte cityCode;
    byte countyCode;
    short mineCode;
    byte shaftCode;  //矿井编号
    byte deviceCode = 0;
    Date time;      //处理数据的时间
    long monthOrder;  //月序号
    short status;
    int output;        //五分钟产量
    String ip;          //IP地址 
    int port;          //端口
    Socket kkSocket = null;
    OutputStream out = null;
    InputStream in = null;
    byte[] data = new byte[26];
    byte oldWkyc = -1;
    int errorTimesPermit=3;    //允许发生错误的最大次数，消息3次发送错误，将舍弃
    int timeOut = 30000;               //Socket超时时间
    int uploadStatus=-1;              //上次传状态
    
    private RealDeviceDao realDevice=null;
    private DatabaseConnectionSQL dc = null;

    public DatabaseConnectionSQL getDc() {
        return dc;
    }

    public void setDc(DatabaseConnectionSQL dc) {
        this.dc = dc;
    }
    
        
    private void setUplaodStatus(int s,int olds){
        //if(s==olds)
        //    return;
        String orgCode;
        orgCode="01010101";        
        try {
            
            realDevice = new RealDeviceDao(dc.getConnection());
            realDevice.updateSCStatus(s, orgCode);
        } catch (Exception ex) {
           logger.error("上传状态更新失败");
        }finally{
            dc.close();
        }
        //olds = s;
    }
    
    @Override
    public void process(String msg) throws OOIIException {

        logger.info("准备上传数据："+msg);
        data[0] = (byte) cityCode;
        data[1] = (byte) countyCode;

        data[2] = NumberUtil.toByteArray(mineCode)[0];
        data[3] = NumberUtil.toByteArray(mineCode)[1];

        data[4] = shaftCode;
        data[5] = 0;   //提升方式

        data[6] = 0;  //月序号
        data[7] = 0;
        data[8] = 0;
        int errorTimes  = 0; //发送失败次数
        while (errorTimes<errorTimesPermit) {   //发送不成功，继续发送规定次数
            try {
                kkSocket = new Socket(ip, port);
                logger.info("连接成功,IP:"+ip+" port:"+port);
                out = kkSocket.getOutputStream();
                logger.info("获得输出流");
                in =  kkSocket.getInputStream();
                logger.debug("获得输出流");
            } catch (UnknownHostException e) {
                setUplaodStatus(1,uploadStatus);
                logger.error("找不到上传服务器主机,IP:"+ip+" port:"+port);
                throw new OOIIException(e);
            } catch (IOException e) {
                setUplaodStatus(1,uploadStatus);
                logger.error("无法获取Socket的输出流,IP:"+ip+" port:"+port);   
                throw new OOIIException(e);
            }
            List<MineData> mineDatas = DataPackage.dePack(msg);  //重复数据要排除
            for (MineData mineData : mineDatas) {
                if (mineData instanceof DataOf5mBean) {
                    DataOf5mBean d5m = (DataOf5mBean) mineData;

                    data[9] = NumberUtil.toBCD((byte) (d5m.getYear() % 100));  //时间
                    data[10] = NumberUtil.toBCD((byte) d5m.getMonth());
                    data[11] = NumberUtil.toBCD((byte) d5m.getDay());
                    data[12] = NumberUtil.toBCD((byte) d5m.getHour());
                    data[13] = NumberUtil.toBCD((byte) d5m.getMin());
                    data[14] = 0;

                    int weight = (int) (d5m.getSumof5min() * 1000+0.001);    //公斤为单位,+0.01纠正偏差,如42.299999这样的数据
                    byte[] r = NumberUtil.toByteArray(weight);
                    data[16] = r[1];  //合计重量
                    data[17] = r[2];
                    data[18] = r[3];


                    data[19] = 0;   //两字节状态
                    data[20] = 0;

                } else if (mineData instanceof CLYCBean) {
                    CLYCBean clyc = (CLYCBean) mineData;

                    data[9] = NumberUtil.toBCD((byte) (clyc.getYear() % 100));  //时间
                    data[10] = NumberUtil.toBCD((byte) clyc.getMonth());
                    data[11] = NumberUtil.toBCD((byte) clyc.getDay());
                    data[12] = NumberUtil.toBCD((byte) clyc.getHour());
                    data[13] = NumberUtil.toBCD((byte) clyc.getMin());
                    data[14] = 0;

                    String status = clyc.getStatus();
                    char wkycs = status.charAt(2);

                    data[16] = 0;  //合计重量
                    data[17] = 0;
                    data[18] = 0;
                    if (wkycs - '0' == oldWkyc) {
                         try {
                            if(in!=null)
                                in.close();
                            if(out!=null)
                                out.close();
                            if(kkSocket!=null)
                                kkSocket.close();
                            //logger.info("关闭连接");
                        } catch (IOException ex) {
                            logger.error("socket关闭错误");
                            //throw new OOIIException(ex);
                            errorTimes++;
                        }
                        return;
                    } else {
                        if (wkycs - '0' == 0) {
                            data[19] = 0x08;
                        } else {
                            data[19] = 0x18;
                        }
                        oldWkyc = (byte)(wkycs-'0');
                    }

                    data[20] = 0x04;


                } else {
                     try {
                        if(in!=null)
                            in.close();
                        if(out!=null)
                            out.close();
                        if(kkSocket!=null)
                            kkSocket.close();
                        //logger.info("关闭连接");
                    } catch (IOException ex) {
                        logger.error("socket关闭错误");
                        //throw new OOIIException(ex);
                        errorTimes++;
                    }
                    return;
                }
            }


            data[15] = 0;  //矿车数量
            data[21] = 0;   //5字节备用
            data[22] = 0;
            data[23] = 0;
            data[24] = 0;
            data[25] = 0;
            try {
                out.write(data);
                out.flush();
                logger.info("发送完毕");
                
                byte[] cbuf = new byte[9];
                
                int length = in.read(cbuf);
                kkSocket.setSoTimeout(timeOut);
                if(length!=0&&length!=-1) {
                    logger.info("收到服务器确认信息");
                    setUplaodStatus(0,uploadStatus);
                     try {
                        if(in!=null)
                            in.close();
                        if(out!=null)
                            out.close();
                        if(kkSocket!=null)
                            kkSocket.close();
                        //logger.info("关闭连接");
                    } catch (IOException ex) {
                        logger.error("socket关闭错误");
                        //throw new OOIIException(ex);
                        errorTimes++;
                    }
                    return;
                }else{
                    errorTimes++;
                    logger.info("未收到服务器确认信息，重新发送");
                    setUplaodStatus(1,uploadStatus);
                }                
            }catch(SocketTimeoutException ste){
                setUplaodStatus(1,uploadStatus);
                logger.info("读取超时");
                errorTimes++;
            }catch (IOException ex) {
                logger.error("Socket写错误");  
                setUplaodStatus(1,uploadStatus);
                //throw new OOIIException(ex);
                errorTimes++;
            } catch(Exception e){
                //e.printStackTrace();
                setUplaodStatus(1,uploadStatus);
                logger.info(e.getMessage());
                errorTimes++;
            }finally {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException ex) {
                    logger.warn("睡眠被中断");
                }
                try {
                    if(in!=null)
                        in.close();
                    if(out!=null)
                        out.close();
                    if(kkSocket!=null)
                        kkSocket.close();
                    //logger.info("关闭连接");
                } catch (IOException ex) {
                    logger.error("socket关闭错误");
                    //throw new OOIIException(ex);
                    errorTimes++;
                }

            }
        }
    }

    public void establishConnecton() {
    }

    @Override
    public void process(List<String> msgs) throws OOIIException {
        for (String msg : msgs) {
            process(msg);
        }
    }

    @Override
    public void initComponent(Properties props) {
    }

    @Override
    public void destroyComponent() throws Exception {
    }

    public byte getCityCode() {
        return cityCode;
    }

    public void setCityCode(byte cityCode) {
        this.cityCode = cityCode;
    }

    public byte getCountyCode() {
        return countyCode;
    }

    public void setCountyCode(byte countyCode) {
        this.countyCode = countyCode;
    }

    public byte getDeviceCode() {
        return deviceCode;
    }

    public void setDeviceCode(byte deviceCode) {
        this.deviceCode = deviceCode;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public short getMineCode() {
        return mineCode;
    }

    public void setMineCode(short mineCode) {
        this.mineCode = mineCode;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public byte getShaftCode() {
        return shaftCode;
    }

    public void setShaftCode(byte shaftCode) {
        this.shaftCode = shaftCode;
    }
}
